/*
 * @Author: 0x9DEFA478
 * @Date: 2025-06-17 23:49:41
 * @LastEditTime: 2025-08-13 22:47:40
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 */
#include "./C_iostream.hpp"
#include "H_Concurrency.hpp"
#if defined(_WIN32)&&(vC_Printf_BypassEncode==0)
#include "../Utility/H_Unicode.h"
#include <stdio.h>
#include <windows.h>
#endif


#if defined(_WIN32)&&(vC_Printf_BypassEncode==0)

class UTF8_To_Local_StareamBuffer:public std::streambuf{
  public:
    UTF8_To_Local_StareamBuffer(FILE* ofile,bool NoBuffer);

  protected:
    virtual int sync()override;
    virtual int_type overflow(int_type c)override;

  private:
    void std_CharOutput(bool IsFlush);

  private:
    H::Lock lock;
    FILE* ofile;

    bool NoBuffer;

    int InBufferIndex;
    char InBuffer[16];
    WCHAR WCharBuffer[16];
    char OutBuffer[16];
};

UTF8_To_Local_StareamBuffer::UTF8_To_Local_StareamBuffer(FILE* ofile,bool NoBuffer):ofile(ofile),NoBuffer(NoBuffer){
}

int UTF8_To_Local_StareamBuffer::sync(){

  lock.Lock();
  if(!NoBuffer){
    std_CharOutput(true);
  }
  lock.Unlock();

  return 0;
}

std::streambuf::int_type UTF8_To_Local_StareamBuffer::overflow(int_type c){
  
  lock.Lock();
  InBuffer[InBufferIndex]=c;
  InBufferIndex++;
  std_CharOutput(NoBuffer);
  lock.Unlock();

  return c;
}

void UTF8_To_Local_StareamBuffer::std_CharOutput(bool IsFlush){
  int res;
  int ValidLength;
  int IsError;

  if((!IsFlush)&&(InBufferIndex<(int)(sizeof(InBuffer)/sizeof(InBuffer[0])/2))){
    return;
  }

  ValidLength=(int)H_UTF8_ValidLength(InBuffer,InBufferIndex,&IsError);

  if(ValidLength>0){
    
    res=MultiByteToWideChar(CP_UTF8,0,InBuffer,ValidLength,WCharBuffer,sizeof(WCharBuffer)/sizeof(WCharBuffer[0]));
    res=WideCharToMultiByte(GetConsoleOutputCP(),0,WCharBuffer,res,OutBuffer,sizeof(OutBuffer)/sizeof(OutBuffer[0]),nullptr,nullptr);
  
    fwrite(OutBuffer,1,res,ofile);

  }

  {
    int length;
    int shiftCount;

    shiftCount=ValidLength+IsError;
    length=InBufferIndex-shiftCount;

    for(int i=0;i<length;i++){
      InBuffer[i]=InBuffer[shiftCount+i];
    }

    InBufferIndex=length;
  }

  if(InBufferIndex>=(int)(sizeof(InBuffer)/sizeof(InBuffer[0])-1)){
    InBufferIndex=0;
  }

}

static UTF8_To_Local_StareamBuffer cout_UTF8_To_Local_StareamBuffer{stdout,false};
static UTF8_To_Local_StareamBuffer clog_UTF8_To_Local_StareamBuffer{stderr,false};
static UTF8_To_Local_StareamBuffer cerr_UTF8_To_Local_StareamBuffer{stderr,true};

#endif


namespace H{

#if defined(_WIN32)&&(vC_Printf_BypassEncode==0)

  std::ostream cout(&cout_UTF8_To_Local_StareamBuffer);
  std::ostream clog(&clog_UTF8_To_Local_StareamBuffer);
  std::ostream cerr(&cerr_UTF8_To_Local_StareamBuffer);

#elif defined(__linux__)
  std::ostream& cout=std::cout;
  std::ostream& clog=std::clog;
  std::ostream& cerr=std::cerr;
#endif

}

